package com.yanqu.road.server.channelserver.manager.activity.entername;

import com.yanqu.road.dao.impl.activity.entername.ChannelEnterNameConfigDaoImpl;
import com.yanqu.road.dao.impl.channelcenter.entername.ActivityGroupMatchDaoImpl;
import com.yanqu.road.dao.impl.channelcenter.entername.UserEnterNameDaoImpl;
import com.yanqu.road.entity.activity.ActivityConfig;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.entername.*;
import com.yanqu.road.entity.enums.eActivityConfigType;
import com.yanqu.road.logic.activity.entername.ChannelEnterNameHelper;
import com.yanqu.road.pb.cross3.activity.EnterNameProto;
import com.yanqu.road.server.channelserver.logic.ChannelMessageHelper;
import com.yanqu.road.server.channelserver.manager.activity.ChannelActivityInfoMgr;
import com.yanqu.road.server.channelserver.manager.activity.entername.rank.EnterNameGroupRank;
import com.yanqu.road.server.protocol.Cross3Protocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class EnterNameModel {

    //配置
    ActivityInfo activityInfo;

    List<ChannelFightMatchRule> ruleList;

    List<ChannelFightZone> zoneList;

    EnterNameGroupCtrl groupCtrl;

    //报名期
    int nameTime;

    //活动期
    int groupTime;

    //连胜积分
    List<Integer> winScoreList;

    //失败积分
    int loseScore;

    public EnterNameModel(ActivityInfo activityInfo, List<ChannelFightMatchRule> ruleList, List<ChannelFightZone> zoneList, EnterNameGroupCtrl groupCtrl) {
        this.activityInfo = activityInfo;
        this.ruleList = ruleList;
        this.zoneList = zoneList;
        this.groupCtrl = groupCtrl;
    }

    //报名信息
    Map<Long, UserEnterName> nameMap = new ConcurrentHashMap<>();

    //分组
    Map<Integer, ActivityGroupMatch> matchMap = new ConcurrentHashMap<>();

    //cache
    //报名统计
    EnterNameProto.EnterNameZoneCountListMsg countListMsg;

  public boolean reloadConfig(){


      return true;
  }


  public boolean init(boolean loadDb){
        if(ruleList == null){
            ruleList = new ChannelEnterNameConfigDaoImpl().getChannelFightMatchRuleList(activityInfo.getActivityId());
        }
        if(zoneList == null){
            zoneList = new ChannelEnterNameConfigDaoImpl().getChannelFightZoneList(activityInfo.getActivityId());
        }

        //时间配置读取
        Map<String, ActivityConfig> activityConfigMap = ChannelActivityInfoMgr.getConfigMap(activityInfo.getActivityId());
        if(activityConfigMap.containsKey(eActivityConfigType.AREAFIGHT_TIME.getName())){
            List<Integer> paramList = StringUtils.stringToIntegerList(activityConfigMap.get(eActivityConfigType.AREAFIGHT_TIME.getName()).getValue(), "\\|");
            nameTime = paramList.get(0);
            groupTime = paramList.get(1);
        }

        if(activityConfigMap.containsKey(eActivityConfigType.AREAFIGHT_SCORE_WIN.getName())){
            winScoreList = StringUtils.stringToIntegerList(activityConfigMap.get(eActivityConfigType.AREAFIGHT_SCORE_WIN.getName()).getValue(), "\\|");
        }

        if(activityConfigMap.containsKey(eActivityConfigType.AREAFIGHT_SCORE_LOSE.getName())){
            loseScore = activityConfigMap.get(eActivityConfigType.AREAFIGHT_SCORE_LOSE.getName()).getIntValue();
        }

        //加载数据库分组信息
        if(loadDb){
            Map<Long, UserEnterName> tempUserMap = new UserEnterNameDaoImpl().getUserEnterName(activityInfo.getActivityId());
            Map<Integer, ActivityGroupMatch> tempMatchMap = new ActivityGroupMatchDaoImpl().getActivityGroupMatch(activityInfo.getActivityId());
            nameMap = tempUserMap;
            matchMap = tempMatchMap;
            initCountListMsg();
        }
        return true;
    }

    public boolean inAddNameTime(){
        long nowTime = System.currentTimeMillis() / 1000;
        //分组前都可以报名
        if(nowTime < (activityInfo.getBeginTime() + groupTime * 60)){
            return true;
        }
        return false;
    }

    //报名
    public int addEnterName(UserEnterName userEnterName){
        if(inAddNameTime()){
            if(userEnterName.getZoneId() <= 0){
                //没有必要的信息，不让报名
                return GameErrorCode.E_ENTER_NAME_ADD_NOT_ZONE;
            }
            nameMap.putIfAbsent(userEnterName.getUserId(), userEnterName);
        }
        return 0;
    }

    //报名
    public List<UserEnterName> addEnterName(List<EnterNameParam> list){
        List<UserEnterName> result = new ArrayList<>();
        if(inAddNameTime()){
            for (EnterNameParam nameParam : list) {
                if(nameParam.getZoneId() > 0 && nameMap.get(nameParam.getUserId()) == null){
                    UserEnterName userEnterName = ChannelEnterNameMgr.initUserEnterName(nameParam);
                    nameMap.put(userEnterName.getUserId(), userEnterName);
                    result.add(userEnterName);
                }
            }
        }
        return result;
    }

    public int getGroupId(int zoneId){
        for (Map.Entry<Integer, ActivityGroupMatch> matchEntry : matchMap.entrySet()) {
            ActivityGroupMatch groupMatch = matchEntry.getValue();
            if(groupMatch.getZoneIdList().contains(zoneId)){
                return groupMatch.getGroupId();
            }
        }
        return 0;
    }

    public ActivityGroupMatch getActivityGroupMatchByMatchGroup(int matchGroupId){
        for (Map.Entry<Integer, ActivityGroupMatch> matchEntry : matchMap.entrySet()) {
            if(matchEntry.getValue().getRankMatchGroupId() == matchGroupId){
                return matchEntry.getValue();
            }
        }
        return null;
    }

    //分组准备
    public void prepareGroup(){

    }

    //分组
    public void grouping(){
        if(nameTime == 0 || groupTime == 0){
            return;
        }
        if(matchMap.size() > 0){
            return;
        }
        //时间未到,提前一分钟
        if(System.currentTimeMillis() / 1000 < (activityInfo.getBeginTime() + ((groupTime - 1) * 60))){
            return;
        }
        if(groupCtrl != null){
            groupCtrl.grouping(this);

            //分发匹配结果
            syncMatchGroupingResult();
        }
    }

    public void syncMatchGroupingResult() {

        EnterNameProto.ChannelEnterNameGroupingSyncMsg.Builder sync = EnterNameProto.ChannelEnterNameGroupingSyncMsg.newBuilder();
        sync.setActivityId(activityInfo.getActivityId());

        for (Map.Entry<Integer, ActivityGroupMatch> matchEntry : matchMap.entrySet()) {
            ActivityGroupMatch match = matchEntry.getValue();
            EnterNameProto.ChannelEnterNameGroupingMsg.Builder builder = EnterNameProto.ChannelEnterNameGroupingMsg.newBuilder();
            builder.setGroupId(match.getGroupId());
            builder.addAllZoneList(match.getZoneIdList());
            builder.setEnemyGroupId(match.getEnemyGroupId());
            sync.addMatch(builder);
        }
        //分发分组名单  渠道-区服
        Map<Integer, Map<Long, List<Long>>> channelServerMap = getChannelServerMap();

        for (Map.Entry<Integer, Map<Long, List<Long>>> entry : channelServerMap.entrySet()) {
            int channelId = entry.getKey();
            ChannelMessageHelper.sendToChannel(YanQuMessageUtils.buildMessage(Cross3Protocol.C3_ENTER_NAME_GROUPING_NAME_SYNC, sync), channelId);
        }
    }

    /**
     * 根据名单整理  渠道-区服-玩家列表
     */
    public Map<Integer, Map<Long, List<Long>>> getChannelServerMap() {
        Map<Integer, Map<Long, List<Long>>> channelServerMap = new HashMap<>();
        for (Map.Entry<Long, UserEnterName> nameEntry : nameMap.entrySet()) {
            UserEnterName userEnterName = nameEntry.getValue();
            if (!channelServerMap.containsKey(userEnterName.getChannelId())) {
                channelServerMap.put(userEnterName.getChannelId(), new HashMap<>());
            }
            if (!channelServerMap.get(userEnterName.getChannelId()).containsKey(userEnterName.getServerId())) {
                channelServerMap.get(userEnterName.getChannelId()).put(userEnterName.getServerId(), new ArrayList<>());
            }
            channelServerMap.get(userEnterName.getChannelId()).get(userEnterName.getServerId()).add(userEnterName.getUserId());
        }
        return channelServerMap;
    }

    /**
     * 根据名单整理  渠道-区服-匹配对阵分组-玩家
     */
    public Map<Integer, Map<Long, Map<Integer, List<Long>>>> getChannelServerGroupMap() {
        Map<Integer, Map<Long, Map<Integer, List<Long>>>> channelServerMap = new HashMap<>();
        for (Map.Entry<Long, UserEnterName> nameEntry : nameMap.entrySet()) {
            UserEnterName userEnterName = nameEntry.getValue();
            if(userEnterName.isGetDisperseGold()){
                continue;
            }
            if (!channelServerMap.containsKey(userEnterName.getChannelId())) {
                channelServerMap.put(userEnterName.getChannelId(), new HashMap<>());
            }
            if (!channelServerMap.get(userEnterName.getChannelId()).containsKey(userEnterName.getServerId())) {
                channelServerMap.get(userEnterName.getChannelId()).put(userEnterName.getServerId(), new HashMap<>());
            }
            ActivityGroupMatch groupMatch = getActivityGroupMatch(userEnterName.getGroupId());
            if (groupMatch == null){
                continue;
            }
            if (!channelServerMap.get(userEnterName.getChannelId()).get(userEnterName.getServerId()).containsKey(groupMatch.getRankMatchGroupId())){
                channelServerMap.get(userEnterName.getChannelId()).get(userEnterName.getServerId()).put(groupMatch.getRankMatchGroupId(), new ArrayList<>());
            }
            channelServerMap.get(userEnterName.getChannelId()).get(userEnterName.getServerId()).get(groupMatch.getRankMatchGroupId()).add(userEnterName.getUserId());
        }
        return channelServerMap;
    }


    /**
     * 渠道跨服重启后请求
     */
    public void syncAllName(int targetChannelId) {
        //分发分组名单  渠道-区服
        Map<Integer, Map<Long, List<Long>>> channelServerMap = getChannelServerMap();

        List<EnterNameProto.ChannelEnterNameGroupingMsg> groupList = new ArrayList<>();
        for (Map.Entry<Integer, ActivityGroupMatch> matchEntry : matchMap.entrySet()) {
            ActivityGroupMatch match = matchEntry.getValue();
            EnterNameProto.ChannelEnterNameGroupingMsg.Builder builder = EnterNameProto.ChannelEnterNameGroupingMsg.newBuilder();
            builder.setGroupId(match.getGroupId());
            builder.addAllZoneList(match.getZoneIdList());
            builder.setEnemyGroupId(match.getEnemyGroupId());
            groupList.add(builder.build());
        }

        for (Map.Entry<Integer, Map<Long, List<Long>>> entry : channelServerMap.entrySet()) {
            int channelId = entry.getKey();
            if(targetChannelId > 0 && targetChannelId != channelId){
                continue;
            }
            for (Map.Entry<Long, List<Long>> listEntry : entry.getValue().entrySet()) {
                EnterNameProto.ChannelEnterNameAllSyncMsg.Builder sync = EnterNameProto.ChannelEnterNameAllSyncMsg.newBuilder();
                sync.addAllGroup(groupList);
                long serverId = listEntry.getKey();
                sync.setActivityId(activityInfo.getActivityId());
                sync.setServerId(serverId);
                for (long userId : listEntry.getValue()) {
                    UserEnterName name = nameMap.get(userId);
                    EnterNameProto.UserEnterNameMsg.Builder builder = ChannelEnterNameHelper.buildUserEnterNameMsg(name);
                    sync.addName(builder);
                }
                ChannelMessageHelper.sendToChannel(YanQuMessageUtils.buildMessage(Cross3Protocol.C3_ENTER_NAME_ALL_NAME_SYNC, sync), channelId);
            }
        }

    }

    public void syncName(int activityId, int channelId, long serverId, List<UserEnterName> list){
        if(list.size() == 0){
            return;
        }
        EnterNameProto.ChannelEnterNameAllSyncMsg.Builder sync = EnterNameProto.ChannelEnterNameAllSyncMsg.newBuilder();
        sync.setActivityId(activityId);
        sync.setServerId(serverId);
        for (UserEnterName name : list) {
            EnterNameProto.UserEnterNameMsg.Builder builder = ChannelEnterNameHelper.buildUserEnterNameMsg(name);
            sync.addName(builder);
        }
        ChannelMessageHelper.sendToChannel(YanQuMessageUtils.buildMessage(Cross3Protocol.C3_ENTER_NAME_BATCH_ADD_FROM_CHANNEL, sync), channelId);

        //自动报名，返回区服，下发给客户端
        EnterNameProto.ChannelEnterNameBatchSyncMsg.Builder gameSync = EnterNameProto.ChannelEnterNameBatchSyncMsg.newBuilder();
        gameSync.setActivityId(activityId);
        gameSync.setServerId(serverId);
        for (UserEnterName name : list) {
            EnterNameProto.ChannelEnterNameMsg.Builder builder = EnterNameProto.ChannelEnterNameMsg.newBuilder();
            builder.setUserId(name.getUserId());
            builder.setZoneId(name.getZoneId());
            gameSync.addName(builder);
        }
        ChannelMessageHelper.sendGamePacket(Protocol.S_ENTER_NAME_NAME_SYNC_FROM_CHANNEL, gameSync, channelId, serverId, 0);
    }

    //需要时，改为定时
    public void initCountListMsg(){
        if(!inAddNameTime()){
            return;
        }
        Map<Integer, Integer> countMap = new HashMap<>();
        for (Map.Entry<Long, UserEnterName> nameEntry : nameMap.entrySet()) {
            UserEnterName userEnterName = nameEntry.getValue();
            int zoneId = userEnterName.getZoneId();
            int old = countMap.getOrDefault(zoneId, 0);
            countMap.put(zoneId, 1 + old);
        }
        EnterNameProto.EnterNameZoneCountListMsg.Builder listBuilder = EnterNameProto.EnterNameZoneCountListMsg.newBuilder();
        listBuilder.setActivityId(activityInfo.getActivityId());
        for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {
            EnterNameProto.EnterNameZoneCountMsg.Builder builder = EnterNameProto.EnterNameZoneCountMsg.newBuilder();
            builder.setZoneId(entry.getKey());
            builder.setCount(entry.getValue());
            listBuilder.addCount(builder);
            ChannelEnterNameMgr.getLogger().info("enter name zoneId {} count {}", entry.getKey(), entry.getValue());
        }
        countListMsg = listBuilder.build();
    }

    public UserEnterName getUserEnterName(long userId){
        return nameMap.get(userId);
    }

    public List<UserEnterName> getUserEnterName(int channelId, long serverId){
        List<UserEnterName> list = new ArrayList<>();
        for (Map.Entry<Long, UserEnterName> entry : nameMap.entrySet()) {
            UserEnterName name = entry.getValue();
            if(name.getServerId() == serverId && name.getChannelId() == channelId){
                list.add(name);
            }
        }
        return list;
    }

    public ActivityGroupMatch getActivityGroupMatch(int groupId){
        return matchMap.get(groupId);
    }

    public void save() {
        for (Map.Entry<Long, UserEnterName> entry : nameMap.entrySet()) {
            UserEnterName data = entry.getValue();
            if(data.isInsertOption()){
                new UserEnterNameDaoImpl().add(data);
            }else if(data.isUpdateOption()){
                new UserEnterNameDaoImpl().update(data);
            }
        }

        for (Map.Entry<Integer, ActivityGroupMatch> entry : matchMap.entrySet()) {
            ActivityGroupMatch data = entry.getValue();
            if(data.isInsertOption()){
                new ActivityGroupMatchDaoImpl().add(data);
            }else if(data.isUpdateOption()){
                new ActivityGroupMatchDaoImpl().update(data);
            }
        }
    }

    public LinkedList<EnterNameGroupRank> initGroupRank(int matchGroupId, int type){
        LinkedList<EnterNameGroupRank> list = new LinkedList<>();
        ActivityGroupMatch match = getActivityGroupMatchByMatchGroup(matchGroupId);
        if(match != null){
            EnterNameGroupRank groupRank = new EnterNameGroupRank();
            groupRank.setGroupId(match.getGroupId());
            groupRank.setLastUpdateTime(System.currentTimeMillis()/1000);
            groupRank.setType(type);
            groupRank.setValue(BigInteger.ZERO);
            list.add(groupRank);

            EnterNameGroupRank groupRank2 = new EnterNameGroupRank();
            groupRank2.setGroupId(match.getEnemyGroupId());
            groupRank2.setLastUpdateTime(System.currentTimeMillis()/1000);
            groupRank2.setType(type);
            groupRank2.setValue(BigInteger.ZERO);
            list.add(groupRank2);
        }
        return list;
    }

    //get  set
    public ActivityInfo getActivityInfo() {
        return activityInfo;
    }

    public void setActivityInfo(ActivityInfo activityInfo) {
        this.activityInfo = activityInfo;
    }

    public List<ChannelFightMatchRule> getRuleList() {
        return ruleList;
    }

    public void setRuleList(List<ChannelFightMatchRule> ruleList) {
        this.ruleList = ruleList;
    }

    public List<ChannelFightZone> getZoneList() {
        return zoneList;
    }

    public void setZoneList(List<ChannelFightZone> zoneList) {
        this.zoneList = zoneList;
    }

    public EnterNameGroupCtrl getGroupCtrl() {
        return groupCtrl;
    }

    public void setGroupCtrl(EnterNameGroupCtrl groupCtrl) {
        this.groupCtrl = groupCtrl;
    }

    public int getNameTime() {
        return nameTime;
    }

    public void setNameTime(int nameTime) {
        this.nameTime = nameTime;
    }

    public int getGroupTime() {
        return groupTime;
    }

    public void setGroupTime(int groupTime) {
        this.groupTime = groupTime;
    }

    public Map<Long, UserEnterName> getNameMap() {
        return nameMap;
    }

    public void setNameMap(Map<Long, UserEnterName> nameMap) {
        this.nameMap = nameMap;
    }

    public Map<Integer, ActivityGroupMatch> getMatchMap() {
        return matchMap;
    }

    public void setMatchMap(Map<Integer, ActivityGroupMatch> matchMap) {
        this.matchMap = matchMap;
    }

    public EnterNameProto.EnterNameZoneCountListMsg getCountListMsg() {
        return countListMsg;
    }

    public List<Integer> getWinScoreList() {
        return winScoreList;
    }

    public void setWinScoreList(List<Integer> winScoreList) {
        this.winScoreList = winScoreList;
    }

    public int getLoseScore() {
        return loseScore;
    }

    public void setLoseScore(int loseScore) {
        this.loseScore = loseScore;
    }

    public void setCountListMsg(EnterNameProto.EnterNameZoneCountListMsg countListMsg) {
        this.countListMsg = countListMsg;
    }
}
